/**
 * Copyright (c) 2010 Simple Graph Tools contributors. All rights reserved.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * 
 *   http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 * $Id$
 */
package org.sgt.coredef.util;

import org.eclipse.emf.common.util.BasicEList;
import org.eclipse.emf.common.util.EList;
import org.eclipse.emf.ecore.EStructuralFeature;
import org.sgt.coredef.CoredefFactory;
import org.sgt.coredef.CoredefPackage;
import org.sgt.coredef.DecomposableEdge;
import org.sgt.coredef.DescribedObject;
import org.sgt.coredef.Edge;
import org.sgt.coredef.ProxyEdge;

/**
 * @author BUTTIGHOFFER-A
 * 
 */
public final class EdgeHelper {

	/**
	 * Helper Class has a private constructor.
	 */
	private EdgeHelper() {
		super();
	}

	/**
	 * Determines whether two {@link Node}s are comparable :
	 * <UL>
	 * <LI>They are the same ( == ) object</LI>
	 * <LI>or are {@link ProxyNode} pointing to the same ( == )
	 * representation.</LI>
	 * <LI>or are {@link DecomposableEdge} pointing to comparable represented
	 * chain.</LI>
	 * </UL>
	 * In the case of {@link ProxyNode} only the representedObject is checked
	 * (constraints and condition on two proxies or a proxy and a node are
	 * ignored) .
	 * 
	 * @param edge1
	 *            the first {@link Node}
	 * @param edge2
	 *            the second {@link Node}
	 * @return true only when objects are comparable.
	 */
	public static boolean areComparable(final Edge edge1, final Edge edge2) {

		if (edge1 == edge2) {
			return true;
		}
		if (edge1 instanceof ProxyEdge) {
			ProxyEdge prox = (ProxyEdge) edge1;
			if (edge2 instanceof ProxyEdge) {
				ProxyEdge prox2 = (ProxyEdge) edge2;
				return prox.getRepresentedObject() == prox2
						.getRepresentedObject();
			} else {
				return prox.getRepresentedObject() == edge2;
			}
		} else if (edge1 instanceof DecomposableEdge) {
			DecomposableEdge decomp = (DecomposableEdge) edge1;
			if (edge2 instanceof ProxyEdge) {
				ProxyEdge prox2 = (ProxyEdge) edge2;
				return decomp == prox2.getRepresentedObject();
			} else if (edge2 instanceof DecomposableEdge) {
				DecomposableEdge decomp2 = (DecomposableEdge) edge2;
				return ChainHelper.areComparable(decomp.getRepresentedChain(),
						decomp2.getRepresentedChain());
			}
		} else {
			if (edge2 instanceof ProxyEdge) {
				ProxyEdge prox2 = (ProxyEdge) edge2;
				return prox2.getRepresentedObject() == edge1;
			}
		}
		return false;
	}

	/**
	 * Creates a {@link ProxyEdge} on given {@link Edge}. If the edge is a
	 * {@link DescribedObject}, the name and summary of the proxy will be
	 * synchronized via the {@link Proxy#syncProxy(EList)} method. Beware that
	 * when the edge is a ProxyEdge, it's representation and not the edge itself
	 * will be used as representation for the returned proxy.
	 * 
	 * @param edge
	 *            to create proxy from.
	 * @return a new proxy on given node.
	 */
	public static ProxyEdge createProxyEdge(final Edge edge) {
		ProxyEdge proxy = CoredefFactory.eINSTANCE.createProxyEdge();
		Edge representation = edge;
		if (edge instanceof ProxyEdge) {
			representation = ((ProxyEdge) edge).getRepresentedObject();
		}
		proxy.setRepresentedObject(representation);
		if (representation instanceof DescribedObject) {
			// Making sure we have a name and summary attributes...
			EList<EStructuralFeature> featuresList 
				= new BasicEList<EStructuralFeature>();
			featuresList
					.add(CoredefPackage.eINSTANCE.getDescribedObject_Name());
			featuresList.add(CoredefPackage.eINSTANCE
					.getDescribedObject_Summary());
			proxy.syncProxy(featuresList);
		}
		return proxy;
	}

}
